package com.cntaiping.workutil.videoanalysis;

import com.cntaiping.analysis.domain.VideoAnalysisDto;
import com.cntaiping.analysis.domain.VideoRequest;
import com.cntaiping.analysis.domain.VideoResponse;
import com.cntaiping.analysis.service.AnalysisCsvService;
import com.cntaiping.analysis.service.VideoBaseService;
import com.cntaiping.analysis.utils.CsvUtils;
import com.cntaiping.analysis.utils.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.awt.geom.Path2D;
import java.io.*;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class VideoBaseServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(VideoBaseServiceImpl.class);

    @Value("${video.path.seat-csv}")
    private String seatCsv;

/*
读取resource路径下的所有文件
    # 监控坐标csv路径,读取camera下的所有csv
    seat-csv: 'doc/camera/camera_*.csv'
    # 物理位置图excel路径
    physical-xlsx: 'doc/seat/seat.xlsx'

    work-dir: '/home/zhaowd1018/video_analysis_output/phone_analysis'
*/
    @Value("${video.path.physical-xlsx}")
    private String physicalExcel;
    @Value("${video.path.seat-csv-0}")
    private String seat0Csv;
    @Value("${video.path.camera-csv-0}")
    private String camera0Csv;
    @Value("${video.path.work-dir}")
    private String workdir;

    @Autowired
    private AnalysisCsvService csvService;

    /**
     * CSV文件列分隔符
     */
    private static final String CSV_COLUMN_SEPARATOR = ",";

    /**
     * CSV文件行分隔符
     */
    private static final String CSV_ROW_SEPARATOR = "\n";


    private Map<String, List<String[]>> videoMap;

    private  Workbook workbook;


    @PostConstruct
    public void loadVideoDate() {
        /**
         * todo csv文件、位置图文件转配置读取
         */

        Map<String, List<String[]>> videoMap = initCsvData();

        if (videoMap.size() > 0) {
            this.videoMap = videoMap;
            logger.info("init csv axis success!");
        }

        Workbook workbook = null;
        try {

            Resource resource = new PathMatchingResourcePatternResolver().getResource(physicalExcel);
            logger.info("load physical-excel seat path : {}", physicalExcel);
            InputStream inputStream = resource.getInputStream();

            if (physicalExcel.toLowerCase().endsWith("xls")) {
                workbook = new HSSFWorkbook(new BufferedInputStream(inputStream));
            } else {
                workbook = new XSSFWorkbook(new BufferedInputStream(inputStream));
            }
        } catch (Exception e) {
            logger.error("init physical-excel seat failed:{}", e.getMessage());
        }
        this.workbook = workbook;

        if (workbook != null) {
            logger.info("init physical-excel seat success!");
        }


    }

    @Override
    public List<VideoResponse> batchSeat(List<VideoRequest> request) {
        List<VideoResponse> responses = new ArrayList<>();
        if (videoMap.size() <= 0) {

            logger.error("csv坐标文件为空!");

            throw new RuntimeException("csv坐标文件为空!");
        }
        if (request != null && request.size() > 0) {
            for (VideoRequest videoRequest : request) {

                VideoResponse response = new VideoResponse();
                response.setP1(videoRequest.getP1());
                response.setP2(videoRequest.getP2());
                response.setCameraId(videoRequest.getCameraId());
                response.setState("0");

                List<String[]> cameraList = videoMap.get(videoRequest.getCameraId());


                if (cameraList != null && cameraList.size() > 0) {

                    List<String[]> pointData = isPointData(cameraList, videoRequest.getP1(), videoRequest.getP2());

                    if (pointData.size() > 0) {
                        /**
                         * 这里说明点在平面内,根据获取到的seat去获取实名
                         */

                        response.setSeat(pointData.get(0)[3]);

                        String name = physicalSeat2Name(pointData.get(0)[3]);
                        if(StringUtils.isBlank(name)){
                            throw new RuntimeException("摄像头:["+videoRequest.getCameraId()+"]位置["+response.getSeat()+"]物理位置匹配异常");
                        }
                        response.setName(name);

                        response.setState("1");

                    }
                }
                responses.add(response);

            }

            logger.info("获取位置信息响应参数:{}", JsonUtil.getFormatJson(responses));
        } else {
            throw new RuntimeException("输入坐标参数为空!");
        }

        return responses;

    }


    public Map<String, List<String[]>> initCsvData() {

        Map<String, List<String[]>> videoMap = new HashMap<>();
        /**
         * 加载所有的camera.csv  key:id,value:list
         */

        try {
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources(seatCsv);

            List<Resource> resourceList = Arrays.stream(resources).collect(Collectors.toList());

            logger.info("load csv axis path : {}", seatCsv);

            if (resourceList.size()>0) {
                for (int i = 0; i < resourceList.size(); i++) {
                        List<String[]> videoList = CsvUtils.readCsvByStream(resourceList.get(i).getInputStream());
                        if (videoList.size() > 0) {
                            videoMap.put(videoList.get(0)[1], videoList);
                            logger.info("{}.csv load axis size:{}", i+1+"/"+resourceList.size(), videoList.size());
                        }
                    }

            }
        } catch (Exception e) {
            logger.error("load csv axis failed!{}", e.getMessage());
            e.printStackTrace();
        }

        return videoMap;
    }

    @Override
    public List<VideoAnalysisDto> parseRealName(List<VideoAnalysisDto> videoAnalysisDtoList, String jobId) {

        /**
         * 根据初始化数据生成坐标、物理位置汇总
         */
        StringBuilder builder = new StringBuilder();
        List<VideoAnalysisDto> dtoList = new ArrayList<>();

        for (int i = 1; i <= this.videoMap.size(); i++) {
            for (String[] seat : this.videoMap.get(String.valueOf(i))) {
                builder.append(StringUtils.join(seat, CSV_COLUMN_SEPARATOR)).append(CSV_ROW_SEPARATOR);
                String key = seat[3];
                String value = physicalSeat2Name(key);
                VideoAnalysisDto dto = new VideoAnalysisDto();
                dto.setSeat(key);
                dto.setName(value);
                if(!dtoList.contains(dto)){
                    dtoList.add(dto);

                }
            }
        }

        String cameraPath = workdir + "/" + jobId  + camera0Csv;
        csvService.createCameraCsv(cameraPath,builder.toString());

        String seatPath = workdir + "/" + jobId + seat0Csv;
        csvService.createSeatCsv(seatPath,dtoList);
        /**
         * todo 未匹配到的坐标点
         */
        List<VideoAnalysisDto> matchAnalysisList = new ArrayList<>();
        List<VideoAnalysisDto> unMatchAnalysisList = new ArrayList<>();

        if (videoAnalysisDtoList != null && videoAnalysisDtoList.size() > 0) {

            for (VideoAnalysisDto videoAnalysisDto : videoAnalysisDtoList) {
                if (StringUtils.isBlank(videoAnalysisDto.getType()) || StringUtils.isBlank(videoAnalysisDto.getAxisX()) || StringUtils.isBlank(videoAnalysisDto.getAxisY()) || StringUtils.isBlank(videoAnalysisDto.getAnalysisTime())) {
                    unMatchAnalysisList.add(videoAnalysisDto);
                    continue;
                }
                List<String[]> cameraList = videoMap.get(videoAnalysisDto.getCamera());

                if (cameraList != null && cameraList.size() > 0) {

                    /**
                     * pointData.size()>0说明存在匹配该点的位置
                     */
                    List<String[]> pointData = isPointData(cameraList, videoAnalysisDto.getAxisX(), videoAnalysisDto.getAxisY());
                    if (pointData.size() > 0) {
                        videoAnalysisDto.setSeat(pointData.get(0)[3]);
                        String name = physicalSeat2Name(pointData.get(0)[3]);
                        if(StringUtils.isBlank(name)){
                            logger.info("========:{}",videoAnalysisDto);
                            throw new RuntimeException("camera:["+videoAnalysisDto.getCamera()+"]position["+videoAnalysisDto.getSeat()+"]The physical location matches failed");
                        }
                        videoAnalysisDto.setName(name);
                        matchAnalysisList.add(videoAnalysisDto);
                    } else {
                        unMatchAnalysisList.add(videoAnalysisDto);
                    }
                } else {
                    unMatchAnalysisList.add(videoAnalysisDto);
                }

            }
            logger.info("Match the coordinate point count:{},The coordinate point is not matched count:{}", matchAnalysisList.size(), unMatchAnalysisList.size());

        }
        return matchAnalysisList;
    }

    public List<String[]> isPointData(List<String[]> cameraList, String axisX, String axisY) {

        return cameraList.stream().filter(camera -> {

            double[] ployX = {Integer.parseInt(camera[5]), Integer.parseInt(camera[8]), Integer.parseInt(camera[11]), Integer.parseInt(camera[14])};
            double[] ployY = {Integer.parseInt(camera[6]), Integer.parseInt(camera[9]), Integer.parseInt(camera[12]), Integer.parseInt(camera[15])};

            int x = Integer.parseInt(axisX);
            int y = Integer.parseInt(axisY);
            return isPointInPolygon(x, y, ployX, ployY, 4);

        }).collect(Collectors.toList());
    }

    public boolean isPointInPolygon(int x, int y, double[] ployX, double[] ployY, int numPoints) {
        Path2D polygon = new Path2D.Double();
        polygon.moveTo(ployX[0], ployY[0]);
        for (int i = 1; i < numPoints; i++) {
            polygon.lineTo(ployX[i], ployY[i]);
        }

        polygon.closePath();

        return polygon.contains(x, y);
    }


    public String physicalSeat2Name(String seat) {
        if("jf".equals(seat)){
            return "张三";
        }
        Cell cell = null;
        try {
            CellReference cellReference = new CellReference(seat);
            int row = cellReference.getRow();
            int col = cellReference.getCol();
            cell = workbook.getSheetAt(0).getRow(row).getCell(col);

            if(cell != null){
                return cell.getStringCellValue();
            }
        }catch (Exception e){
            logger.error("An exception occurred when the coordinates were converted to real names:{}",e.getMessage());
        }

        return null;

    }


}
